package com.gomoku.common.exception;

import com.gomoku.common.Result;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;


import java.util.Set;
import java.util.UUID;

/**
 * 全局异常处理器
 * 统一处理系统中的各种异常
 * 
 * @author gomoku
 * @version 1.0.0
 * @since 2024-01-01
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理业务异常
     * 
     * @param e 业务异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Result<Object>> handleBusinessException(BusinessException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.warn("业务异常 - TraceId: {}, ErrorCode: {}, Message: {}, URI: {}", 
                traceId, e.getErrorCode(), e.getErrorMessage(), request.getRequestURI());
        
        Result<Object> result = Result.error(e.getErrorCode(), e.getErrorMessage());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理参数验证异常
     * 
     * @param e 参数验证异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(ValidationException.class)
    public ResponseEntity<Result<Object>> handleValidationException(ValidationException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.warn("参数验证异常 - TraceId: {}, ErrorCode: {}, Message: {}, URI: {}", 
                traceId, e.getErrorCode(), e.getErrorMessage(), request.getRequestURI());
        
        Result<Object> result = Result.error(e.getErrorCode(), e.getErrorMessage());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理认证异常
     * 
     * @param e 认证异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity<Result<Object>> handleAuthenticationException(AuthenticationException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.warn("认证异常 - TraceId: {}, ErrorCode: {}, Message: {}, URI: {}", 
                traceId, e.getErrorCode(), e.getErrorMessage(), request.getRequestURI());
        
        Result<Object> result = Result.error(e.getErrorCode(), e.getErrorMessage());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);
    }

    /**
     * 处理系统异常
     * 
     * @param e 系统异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(SystemException.class)
    public ResponseEntity<Result<Object>> handleSystemException(SystemException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.error("系统异常 - TraceId: {}, ErrorCode: {}, Message: {}, URI: {}", 
                traceId, e.getErrorCode(), e.getErrorMessage(), request.getRequestURI(), e);
        
        Result<Object> result = Result.error(e.getErrorCode(), e.getErrorMessage());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }

    /**
     * 处理基础异常
     * 
     * @param e 基础异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(BaseException.class)
    public ResponseEntity<Result<Object>> handleBaseException(BaseException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.warn("基础异常 - TraceId: {}, ErrorCode: {}, Message: {}, URI: {}", 
                traceId, e.getErrorCode(), e.getErrorMessage(), request.getRequestURI());
        
        Result<Object> result = Result.error(e.getErrorCode(), e.getErrorMessage());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理参数绑定异常
     * 
     * @param e 参数绑定异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(BindException.class)
    public ResponseEntity<Result<Object>> handleBindException(BindException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        StringBuilder errorMessage = new StringBuilder("参数验证失败: ");
        
        for (FieldError fieldError : e.getFieldErrors()) {
            errorMessage.append(fieldError.getField())
                       .append(" ")
                       .append(fieldError.getDefaultMessage())
                       .append("; ");
        }
        
        logger.warn("参数绑定异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, errorMessage.toString(), request.getRequestURI());
        
        Result<Object> result = Result.paramError(errorMessage.toString());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理方法参数验证异常
     * 
     * @param e 方法参数验证异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Result<Object>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        StringBuilder errorMessage = new StringBuilder("参数验证失败: ");
        
        for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
            errorMessage.append(fieldError.getField())
                       .append(" ")
                       .append(fieldError.getDefaultMessage())
                       .append("; ");
        }
        
        logger.warn("方法参数验证异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, errorMessage.toString(), request.getRequestURI());
        
        Result<Object> result = Result.paramError(errorMessage.toString());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理约束违反异常
     * 
     * @param e 约束违反异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Result<Object>> handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        StringBuilder errorMessage = new StringBuilder("参数验证失败: ");
        
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            errorMessage.append(violation.getPropertyPath())
                       .append(" ")
                       .append(violation.getMessage())
                       .append("; ");
        }
        
        logger.warn("约束违反异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, errorMessage.toString(), request.getRequestURI());
        
        Result<Object> result = Result.paramError(errorMessage.toString());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理方法参数类型不匹配异常
     * 
     * @param e 方法参数类型不匹配异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<Result<Object>> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        String errorMessage = String.format("参数类型错误: %s 应该是 %s 类型", 
                e.getName(), e.getRequiredType().getSimpleName());
        
        logger.warn("方法参数类型不匹配异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, errorMessage, request.getRequestURI());
        
        Result<Object> result = Result.paramError(errorMessage);
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理非法参数异常
     * 
     * @param e 非法参数异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Result<Object>> handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.warn("非法参数异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, e.getMessage(), request.getRequestURI());
        
        Result<Object> result = Result.paramError(e.getMessage());
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 处理空指针异常
     * 
     * @param e 空指针异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<Result<Object>> handleNullPointerException(NullPointerException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.error("空指针异常 - TraceId: {}, URI: {}", traceId, request.getRequestURI(), e);
        
        Result<Object> result = Result.systemError("系统内部错误，请联系管理员");
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }

    /**
     * 处理运行时异常
     * 
     * @param e 运行时异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Result<Object>> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.error("运行时异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, e.getMessage(), request.getRequestURI(), e);
        
        Result<Object> result = Result.systemError("系统运行异常，请联系管理员");
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }

    /**
     * 处理其他所有异常
     * 
     * @param e 异常
     * @param request HTTP请求
     * @return 统一返回结果
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Result<Object>> handleException(Exception e, HttpServletRequest request) {
        String traceId = generateTraceId();
        logger.error("未知异常 - TraceId: {}, Message: {}, URI: {}", 
                traceId, e.getMessage(), request.getRequestURI(), e);
        
        Result<Object> result = Result.systemError("系统异常，请联系管理员");
        result.setTraceId(traceId);
        
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }

    /**
     * 生成追踪ID
     * 
     * @return 追踪ID
     */
    private String generateTraceId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }
}
